#ifndef __M_VHOST_H__
#define __M_VHOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace yqx{
    class VirtualHost{
        public:
            using ptr = std::shared_ptr<VirtualHost>;
            VirtualHost(const std::string& basedir, const std::string& dbfile):
            _emp(std::make_shared<ExchangeManager>(dbfile)),
            _qmp(std::make_shared<MsgQueueManager>(dbfile)),
            _bmp(std::make_shared<BindingManager>(dbfile)),
            _mmp(std::make_shared<MessageManager>(basedir))    
            {
                //获取所有队列信息，通过队列名称恢复历史消息数据
                QueueMap qm = _qmp->getAllQueues();
                for(auto& q: qm){
                    _mmp->initQueueMessage(q.first);
                }
            }
            //声明一个交换机
            bool declareExchange(const std::string& name, ExchangeType type, bool durable, bool auto_delete){
                return _emp->declareExchange(name, type, durable, auto_delete);
            }
            //删除一个交换机
            void deleteExchange(const std::string& ename){
                //除了删除一个交换机，还要删除其相关的绑定信息，但不能删除其绑定的队列
                _bmp->removeExchangeBindings(ename);
                _emp->deleteExchange(ename);

            }
            //声明一个队列
            bool declareQueue(const std::string& qname, bool durable, bool exclusive, bool auto_delete){
                _mmp->initQueueMessage(qname);
                return _qmp->declareQueue(qname, durable, exclusive, auto_delete);
            }
            //声明一个交换机
            void deleteQueue(const std::string& qname){
                _mmp->destroyQueueMessage(qname);
                _bmp->removeMsgQueueBindings(qname);
                _qmp->deleteQueue(qname);
            }
            //绑定
            bool bind(const std::string& ename, const std::string& qname, const std::string& binding_key){
                Exchange::ptr ep = _emp->selectExchange(ename);
                if(ep == nullptr){
                    LOG("绑定队列失败，交换机<%s>不存在！", ename.c_str());
                    return false;
                }
                MsgQueue::ptr mqp = _qmp->selectQueue(qname);
                if(mqp == nullptr){
                    LOG("绑定队列失败，队列<%s>不存在！", qname.c_str());
                    return false;
                }
                return _bmp->bind(ename, qname, binding_key, ep->_durable && mqp->_durable);
            }
            //解绑
            void unbind(const std::string& ename, const std::string& qname){
                return _bmp->unbind(ename, qname);
            }
            //获取一个队列信息
            MsgQueue::ptr getQueue(const std::string& qname){
                return _qmp->selectQueue(qname);
            }
            //获取所有队列信息
            QueueMap getAllQueues(){
                return _qmp->getAllQueues();
            }
            //获取一个交换机的信息
            Exchange::ptr getExchange(const std::string& ename){
                return _emp->selectExchange(ename);
            }
            //获取一个交换机所有的绑定信息
            MsgQueueBindingMap getExchangeBindings(const std::string& ename){
                return _bmp->getExchangeBindings(ename);
            }
            //发布一个消息到队列
            bool basicPublish(const std::string& qname, BasicProperties* bp, const std::string& body){
                MsgQueue::ptr mqp = _qmp->selectQueue(qname);
                if(mqp == nullptr){
                    LOG("绑定队列失败，队列<%s>不存在！", qname.c_str());
                    return false;
                }
                return _mmp->insert(qname, bp, body, mqp->_durable);
            }
            //取出一个队列头部的消息
            MessagePtr basicConsume(const std::string& qname){
                return _mmp->front(qname);
            }
            //确认一个消息
            void basicAck(const std::string& qname, const std::string& msg_id){
                _mmp->ack(qname, msg_id);
            }
        private:
            ExchangeManager::ptr _emp;
            MsgQueueManager::ptr _qmp;
            BindingManager::ptr _bmp;
            MessageManager::ptr _mmp;
    };
}
#endif